/**
* @file	gen_input.c
* @author Jan Sliacky
* 
* Generate input for load-balancing model
*
* April 2010
*
* Copyright (c) 2009 by Jan Sliacky
* All rights reserved.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>
#include <stdbool.h>
#include <math.h>
#include "globals.h"
#include "work.h"

_Bool genNewTasks = false;
_Bool genNewProbs = false;
_Bool genNewFalls = false;
_Bool genNewDurations = false;

/**
 * Read input file and return structure with parameters
 * @author Jan Sliacky
 * @param	config		configuration structure
 * @param	filename	file name of input file
 * @return structure with input parameters
 */
init_config* readInputFile(init_config* config, char* filename) {
    FILE* sfile = NULL;
    int i, j;
    int proc;
    char c[100];
    char spom[20];

    /* open source file*/
    sfile = fopen(filename, "r");
    if (sfile == NULL) {
        printf("Error: Input file has probably wrong path\n\n");
        exit(EXIT_FAILURE);
    }

    fgets(c, 100, sfile);
    sscanf(c,"LOG_LEVEL=%s\n", spom);
    /* load log level */
    if (strcmp(spom,"trace")==0) {
        config->logLevel = trace;
    } else
        if (strcmp(spom,"debug")==0) {
            config->logLevel = debug;
        } else
            if (strcmp(spom,"msg")==0) {
                config->logLevel = msg;
            } else
                if (strcmp(spom,"info")==0) {
                    config->logLevel = info;
                } else
                    if (strcmp(spom,"error")==0) {
                        config->logLevel = error;
                    } else
                        if (strcmp(spom,"none")==0) {
                            config->logLevel = none;
                        }
    fscanf(sfile, "NR_CORES=%d\n", &config->nHwCores);
    fscanf(sfile, "LATENCY=%lf\n", &config->latency);
    fgets(c, 100, sfile);
    sscanf(c,"TSKS_AMOUNT=%s\n", spom);
    if (strcmp(spom,"one") == 0) {
        config->amount = one;
    } else
        if (strcmp(spom,"npart") == 0) {
            config->amount = npart;
        } else
            if (strcmp(spom,"all") == 0) {
                config->amount = all;
            }
    fscanf(sfile, "FORGET_STATUSES=%d\n", &config->forgetStatuses);
    fscanf(sfile, "GET_IMMEDIATELY=%d\n", &config->takeAll);
    fscanf(sfile, "NR_PROCS=%d\n", &config->nProcs);
    fscanf(sfile, "NR_TASKS=%d\n", &config->nTasks);
    fscanf(sfile, "MU_TASKS=%f SIG_TASKS=%f\n", &config->muTasks, &config->sigTasks);
    fscanf(sfile, "MU_FALLS_PROB=%f SIG_FALLS_PROB=%f\n", &config->muFallProb, &config->sigFallProb);
    fscanf(sfile, "MU_FALLS_DUR=%f SIG_FALLS_DUR=%f\n", &config->muFallDur, &config->sigFallDur);
    fscanf(sfile, "SIG_NEXTFALL=%f\n", &config->sigNextFall);
    fscanf(sfile, "\n------ FALL PROBABILITIES -----\n");
    for (i = 0; i < config->nProcs; i++) {
        fscanf(sfile, "%f ", &config->procFallProbs[i]);
    }
    fscanf(sfile, "\n------------ FALLS ------------\n");
    for (i = 0; i < config->nProcs; i++) {
        fscanf(sfile, "P%d ", &proc);
        for (j = 0; j < RANDOMFALLSCOUNT; j++) {
            fscanf(sfile, "%f ", &config->fallProbs[proc][j]);
        }
        fscanf(sfile, "\n");
    }
    fscanf(sfile, "\n---------- DURATIONS ----------\n");
    for (i = 0; i < config->nProcs; i++) {
        fscanf(sfile, "P%d ", &proc);
        for (j = 0; j < RANDOMFALLSCOUNT; j++) {
            fscanf(sfile, "%f ", &config->fallDur[proc][j]);
        }
        fscanf(sfile, "\n");
    }
    fscanf(sfile,"\n------ TASKS COMPLEXITIES -----\n");
    for (i = 0; i < config->nTasks; i++) {
        fscanf(sfile, "%f ", &config->tasksArray[i]);
    }
    fclose(sfile);
    return(config);
}

/**
 * Save input file
 * @author Jan Sliacky
 * @param	config		configuration structure with parameters
 * @param	filename	file name of output file
 */
void writeInputFile(init_config* config, char* filename) {
    FILE* dfile = NULL;
    int i, j;
    char* spom;

    /* create input file */
    dfile = fopen(filename, "w");
    if (dfile == NULL) {
        printf("Error in creating input file\n");
        exit(EXIT_FAILURE);
    }

    /* load log level */
    if (config->logLevel == trace) {
        spom = "trace";
    } else
        if (config->logLevel == debug) {
            spom = "debug";
        } else
            if (config->logLevel == msg) {
                spom = "msg";
            } else
                if (config->logLevel == info) {
                    spom = "info";
                } else
                    if (config->logLevel == error) {
                        spom = "error";
                    } else
                        if (config->logLevel == none) {
                            spom = "none";
                        }
    fprintf(dfile, "LOG_LEVEL=%s\n", spom);
    fprintf(dfile, "NR_CORES=%d\n", config->nHwCores);
    fprintf(dfile, "LATENCY=%.3lf\n", config->latency);
    if (config->amount == one) {
        spom = "one";
    } else
        if (config->amount == npart) {
            spom = "npart";
        } else
            if (config->amount == all) {
                spom = "all";
            }
    fprintf(dfile, "TSKS_AMOUNT=%s\n", spom);
    fprintf(dfile, "FORGET_STATUSES=%d\n", config->forgetStatuses);
    fprintf(dfile, "GET_IMMEDIATELY=%d\n", config->takeAll);
    fprintf(dfile, "NR_PROCS=%d\n", config->nProcs);
    fprintf(dfile, "NR_TASKS=%d\n", config->nTasks);
    fprintf(dfile, "MU_TASKS=%.2f SIG_TASKS=%.2f\n", config->muTasks, config->sigTasks);
    fprintf(dfile, "MU_FALLS_PROB=%.2f SIG_FALLS_PROB=%.2f\n", config->muFallProb, config->sigFallProb);
    fprintf(dfile, "MU_FALLS_DUR=%.2f SIG_FALLS_DUR=%.2f\n", config->muFallDur, config->sigFallDur);
    fprintf(dfile, "SIG_NEXTFALL=%.2f\n", config->sigNextFall);
    fprintf(dfile, "\n------ FALL PROBABILITIES -----\n");
    for (i = 0; i < config->nProcs; i++) {
        fprintf(dfile, "%.2f ", config->procFallProbs[i]);
    }
    fprintf(dfile, "\n");
    fprintf(dfile, "\n------------ FALLS ------------\n");
    for (i = 0; i < config->nProcs; i++) {
        fprintf(dfile, "P%d ", i);
        for (j = 0; j < RANDOMFALLSCOUNT; j++) {
            fprintf(dfile, "%.2f ", config->fallProbs[i][j]);
        }
        fprintf(dfile, "\n");
    }
    fprintf(dfile, "\n---------- DURATIONS ----------\n");
    for (i = 0; i < config->nProcs; i++) {
        fprintf(dfile, "P%d ", i);
        for (j = 0; j < RANDOMFALLSCOUNT; j++) {
            fprintf(dfile, "%.2f ", config->fallDur[i][j]);
        }
        fprintf(dfile, "\n");
    }
    fprintf(dfile, "\n------ TASKS COMPLEXITIES -----\n");
    for (i = 0; i < config->nTasks; i++) {
        fprintf(dfile, "%.2f ", config->tasksArray[i]);
    }
    fclose(dfile);
}

/**
 * Creates input file from inputs variables
 * @author Jan Sliacky
 * @param	config		configuration structure with parameters
 */
void makeInputFile(init_config* config) {
    int i;
    int j;
    init_config* conf_old;

    /* open source file*/
    if (config->sourceFile != NULL) {
        conf_old = (init_config*)malloc(sizeof(init_config));
        conf_old = readInputFile(conf_old, config->sourceFile);

        if (config->nProcs != -1) {
            conf_old->nProcs = config->nProcs;
        } else {
            genNewProbs = true;
            genNewFalls = true;
            genNewDurations =true;
        }
        if (config->nHwCores != -1) {
            conf_old->nHwCores = config->nHwCores;
        }
        if (config->latency != -1) {
            conf_old->latency = config->latency;
        }
        if (config->amount != no_amount) {
            conf_old->amount = config->amount;
        }
        if (config->forgetStatuses == -1) {
            conf_old->forgetStatuses = 0;
        }
        if (config->takeAll == -1) {
            conf_old->takeAll = 0;
        }
        if (config->nTasks != -1) {
            conf_old->nTasks = config->nTasks;
        } else {
            genNewTasks = true;
        }
        if (config->muTasks != -1) {
            conf_old->muTasks = config->muTasks;
        } else {
            genNewTasks = true;
        }
        if (config->sigTasks != -1) {
            conf_old->sigTasks = config->sigTasks;
        } else {
            genNewTasks = true;
        }
        if (config->muFallProb != -1) {
            conf_old->muFallProb = config->muFallProb;
        } else {
            genNewProbs = true;
            genNewFalls = true;
        }
        if (config->sigFallProb != -1) {
            conf_old->sigFallProb = config->sigFallProb;
        } else {
            genNewProbs = true;
            genNewFalls = true;
        }
        if (config->muFallDur != -1) {
            conf_old->muFallDur = config->muFallDur;
        } else {
            genNewProbs = true;
            genNewDurations = true;
        }
        if (config->sigFallDur != -1) {
            conf_old->sigFallDur = config->sigFallDur;
        } else {
            genNewProbs = true;
            genNewDurations = true;
        }
        if (config->sigNextFall != -1) {
            conf_old->sigNextFall = config->sigNextFall;
        } else {
            genNewProbs = true;
            genNewFalls = true;
        }
        if (config->logLevel != no_level) {
            conf_old->logLevel = config->logLevel;
        }
        if (genNewProbs) {
            printf("generating new proc fall probabilities ...");
            for (i = 0; i < conf_old->nProcs; i++) {
                conf_old->procFallProbs[i] = fabs(gauss(conf_old->muFallProb, conf_old->sigFallProb));
            }
            printf("OK\n");
        }
        if (genNewTasks) {
            printf("generating new task complexities ...");
            for (i = 0; i < conf_old->nTasks; i++) {
                conf_old->tasksArray[i] = fabs(gauss(conf_old->muTasks, conf_old->sigTasks));
                if (conf_old->tasksArray[i] < MINTASKCOMPLEXITY) {
                    conf_old->tasksArray[i] = MINTASKCOMPLEXITY;
                }
            }
            printf("OK\n");
        }
        if (genNewFalls) {
            printf("generating new fall times ...");
            for (i = 0; i < conf_old->nProcs; i++) {
                for (j = 0; j < RANDOMFALLSCOUNT; j++) {
                    conf_old->fallProbs[i][j] = fabs(gauss(conf_old->procFallProbs[i], conf_old->sigNextFall));
                    if (conf_old->fallProbs[i][j] < MINFALLTIME) {
                        conf_old->fallProbs[i][j] = MINFALLTIME;
                    }
                }
            }
            printf("OK\n");
        }
        if (genNewDurations) {
            printf("generating new fall durations ...");
            for (i = 0; i < conf_old->nProcs; i++) {
                for (j = 0; j < RANDOMFALLSCOUNT; j++) {
                    conf_old->fallDur[i][j] = fabs(gauss(conf_old->muFallDur, conf_old->sigFallDur));
                    if (conf_old->fallDur[i][j] < MINDURTIME) {
                        conf_old->fallDur[i][j] = MINDURTIME;
                    }
                }
            }
            printf("OK\n");
        }
        writeInputFile(conf_old, config->outputFile);
        free(conf_old);
    } else {
        /* defaults */
        if (config->nProcs == -1)
            config->nProcs = 1;
        if (config->nTasks == -1)
            config->nTasks = 1;
        if (config->nHwCores == -1)
            config->nHwCores = 1;
        if (config->latency == -1)
            config->latency = 0;
        if (config->amount == no_amount)
            config->amount = npart;
        if (config->forgetStatuses == -1)
            config->forgetStatuses = 0;
        if (config->takeAll == -1)
            config->takeAll = 0;
        if (config->muTasks == -1)
            config->muTasks = 1;
        if (config->sigTasks == -1)
            config->sigTasks = 0;
        if (config->muFallProb == -1)
            config->muFallProb = 0;
        if (config->sigFallProb == -1)
            config->sigFallProb = 0;
        if (config->muFallDur == -1)
            config->muFallDur = 1;
        if (config->sigFallDur == -1)
            config->sigFallDur = 0;
        if (config->sigNextFall == -1)
            config->sigNextFall = 0;
        if (config->logLevel == no_level)
            config->logLevel = info;

        printf("generating new proc fall probabilities ...");
        for (i = 0; i < config->nProcs; i++) {
            config->procFallProbs[i] = fabs(gauss(config->muFallProb, config->sigFallProb));
        }
        printf("OK\n");
        printf("generating new fall times ...");
        for (i = 0; i < config->nProcs; i++) {
            for (j = 0; j < RANDOMFALLSCOUNT; j++) {
                config->fallProbs[i][j] = fabs(gauss(config->procFallProbs[i], config->sigNextFall));
                if (config->fallProbs[i][j] < MINFALLTIME) {
                    config->fallProbs[i][j] = MINFALLTIME;
                }
            }
        }
        printf("OK\n");
        printf("generating new fall durations ...");
        for (i = 0; i < config->nProcs; i++) {
            for (j = 0; j < RANDOMFALLSCOUNT; j++) {
                config->fallDur[i][j] = fabs(gauss(config->muFallDur, config->sigFallDur));
                if (config->fallDur[i][j] < MINDURTIME) {
                    config->fallDur[i][j] = MINDURTIME;
                }
            }
        }
        printf("OK\n");
        printf("generating new task complexities ...");
        for (i = 0; i < config->nTasks; i++) {
            config->tasksArray[i] = fabs(gauss(config->muTasks, config->sigTasks));
            if (config->tasksArray[i] < MINTASKCOMPLEXITY) {
                config->tasksArray[i] = MINTASKCOMPLEXITY;
            }
        }
        printf("OK\n");
        writeInputFile(config, config->outputFile);
    }
}
